package org.btik.espidf.run.config.custom;

import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.configurations.PathEnvironmentVariableUtil;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.VerticalFlowLayout;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.util.ui.JBUI;
import org.apache.commons.lang3.StringUtils;
import org.btik.espidf.run.config.EspIdfDebugRunConfig;
import org.btik.espidf.run.config.model.CustomDebugConfigModel;
import org.btik.espidf.service.IdfProjectConfigService;
import org.btik.espidf.state.model.IdfProfileInfo;
import org.btik.espidf.ui.componets.TextFieldFileChooser;
import org.btik.espidf.service.IdfEnvironmentService;
import org.btik.espidf.service.IdfSysConfService;
import org.btik.espidf.util.EspIdfProjectUtil;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.Map;

import static org.btik.espidf.util.I18nMessage.$i18n;
import static org.btik.espidf.util.UIUtils.createConstraints;
import static org.btik.espidf.util.UIUtils.i18nLabel;

/**
 * @author lustre
 * @since 2024/9/2 22:26
 */
public class EspIdfCustomDebugSettingEditor extends SettingsEditor<EspIdfDebugRunConfig<CustomDebugConfigModel>> {

    private final JPanel rootPanel;

    private final EnvironmentVariablesComponent envComponent;

    private final JTextField arguments = new JTextField();
    private final TextFieldFileChooser appElf;
    private final TextFieldFileChooser bootloaderElf;
    private final TextFieldFileChooser romElf;
    private final TextFieldFileChooser gdb;
    private final JButton setDefault = new JButton();
    private final Project project;

    public EspIdfCustomDebugSettingEditor(@NotNull Project project) {
        this.project = project;
        rootPanel = new JPanel(new VerticalFlowLayout(0, 2));
        envComponent = new EnvironmentVariablesComponent();
        envComponent.getLabel().setVisible(false);
        JPanel wrapper = new JPanel(new GridLayoutManager(7, 2, JBUI.insetsTop(16), -1, -1));

        int rowIndex = 0;

        wrapper.add(i18nLabel("esp.idf.debug.openocd.arguments"), createConstraints(rowIndex, 0));
        GridConstraints openocdArgConstraints = createConstraints(rowIndex, 1);
        openocdArgConstraints.setFill(GridConstraints.FILL_HORIZONTAL);
        openocdArgConstraints.setHSizePolicy(GridConstraints.SIZEPOLICY_WANT_GROW);
        wrapper.add(arguments, openocdArgConstraints);
        rowIndex++;

        wrapper.add(i18nLabel("esp.idf.debug.app_elf"), createConstraints(rowIndex, 0));
        GridConstraints appElfConstraints = createConstraints(rowIndex, 1);
        appElfConstraints.setFill(GridConstraints.FILL_HORIZONTAL);
        appElfConstraints.setHSizePolicy(GridConstraints.SIZEPOLICY_WANT_GROW);
        appElf = new TextFieldFileChooser();
        appElf.addActionListener(project, newElfFileChooser($i18n("select.elf.path"), $i18n("select.idf.path.for.idf")));
        wrapper.add(appElf, appElfConstraints);
        rowIndex++;

        wrapper.add(i18nLabel("esp.idf.debug.bootloader_elf"), createConstraints(rowIndex, 0));
        GridConstraints bootLoaderConstraints = createConstraints(rowIndex, 1);
        bootLoaderConstraints.setFill(GridConstraints.FILL_HORIZONTAL);
        bootLoaderConstraints.setHSizePolicy(GridConstraints.SIZEPOLICY_WANT_GROW);
        bootloaderElf = new TextFieldFileChooser();
        bootloaderElf.addActionListener(project, newElfFileChooser($i18n("select.elf.path"), $i18n("esp.idf.debug.bootloader_elf.select")));
        wrapper.add(bootloaderElf, bootLoaderConstraints);
        rowIndex++;

        wrapper.add(i18nLabel("esp.idf.debug.rom_elf"), createConstraints(rowIndex, 0));
        GridConstraints romElfConstraints = createConstraints(rowIndex, 1);
        romElfConstraints.setFill(GridConstraints.FILL_HORIZONTAL);
        romElfConstraints.setHSizePolicy(GridConstraints.SIZEPOLICY_WANT_GROW);
        romElf = new TextFieldFileChooser();
        romElf.addActionListener(project, newElfFileChooser($i18n("select.elf.path"), $i18n("esp.idf.debug.rom_elf.select")));
        wrapper.add(romElf, romElfConstraints);
        rowIndex++;

        wrapper.add(i18nLabel("esp.idf.debug.gdb"), createConstraints(rowIndex, 0));
        GridConstraints gdbArgConstraints = createConstraints(rowIndex, 1);
        gdbArgConstraints.setFill(GridConstraints.FILL_HORIZONTAL);
        gdbArgConstraints.setHSizePolicy(GridConstraints.SIZEPOLICY_WANT_GROW);
        gdb = new TextFieldFileChooser();
        FileChooserDescriptor gdbChooser = new FileChooserDescriptor(true, false, false, false, false, false)
                .withTitle($i18n("select.esp.gdb.path")).withDescription($i18n("select.esp.gdb.path"));
        gdb.addActionListener(project, gdbChooser);
        wrapper.add(gdb, gdbArgConstraints);
        rowIndex++;

        wrapper.add(i18nLabel("esp.idf.debug.openocd.environment.variables"), createConstraints(rowIndex, 0));
        GridConstraints envConstraints = createConstraints(rowIndex, 1);
        envConstraints.setFill(GridConstraints.FILL_HORIZONTAL);
        envConstraints.setHSizePolicy(GridConstraints.SIZEPOLICY_WANT_GROW);
        wrapper.add(envComponent, envConstraints);
        rowIndex++;

        wrapper.add(new JLabel(""), createConstraints(rowIndex, 0));
        wrapper.add(setDefault, createConstraints(rowIndex, 1));
        setDefault.setText($i18n("esp.idf.debug.set.default"));

        rootPanel.add(wrapper, BorderLayout.CENTER);

        bindAction();
    }


    private void bindAction() {
        setDefault.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                try {
                    setDefault.setEnabled(false);
                    initValue();
                } finally {
                    setDefault.setEnabled(true);
                }
            }
        });
        installWatcher(arguments);
        installWatcher(appElf);
        installWatcher(bootloaderElf);
        installWatcher(romElf);
        installWatcher(gdb);
    }

    private void initValue() {
        CustomDebugConfigModel customDebugConfigModel = EspIdfProjectUtil.syncProjectDesc(project);
        if (customDebugConfigModel == null) {
            return;
        }
        appElf.setText(customDebugConfigModel.getAppElf());
        appElf.setRootDir(EspIdfProjectUtil.getFileInCurrentBuildDir(project, "/"));
        bootloaderElf.setText(customDebugConfigModel.getBootloaderElf());
        String target = customDebugConfigModel.getTarget();

        String romElfDir = customDebugConfigModel.getRomElfDir();
        String romElfPeFix = target + '_';
        File romElfDirFile = new File(romElfDir);
        String[] list = romElfDirFile.list();
        if (list != null) {
            for (String elfFiles : list) {
                if (elfFiles.startsWith(romElfPeFix)) {
                    romElf.setText(elfFiles);
                }
            }
            romElf.setRootDir(romElfDirFile);
        }
        IdfSysConfService service = ApplicationManager.getApplication().getService(IdfSysConfService.class);
        String gdbExecutable = service.getGdbExecutable(target);
        gdb.setText(gdbExecutable);
        Map<String, String> environments = project.getService(IdfEnvironmentService.class).getEnvironments();
        String path = environments.get("Path");
        if (path == null) {
            path = environments.get("PATH");
        }
        if (path == null) {
            return;
        }
        File gdbFile = PathEnvironmentVariableUtil.findInPath(gdbExecutable, path, null);
        if (gdbFile != null) {
            gdb.setRootDir(gdbFile.getParentFile());
        }

    }

    @Override
    protected void resetEditorFrom(@NotNull EspIdfDebugRunConfig<CustomDebugConfigModel> espIdfDebugRunConfig) {
        CustomDebugConfigModel configDataModel = espIdfDebugRunConfig.getConfigDataModel();
        if (configDataModel == null) {
            initValue();
            return;
        }
        envComponent.setEnvData(configDataModel.getEnvData());
        arguments.setText(configDataModel.getOpenOcdArguments());
        appElf.setText(configDataModel.getAppElf());
        romElf.setText(configDataModel.getRomElf());
        bootloaderElf.setText(configDataModel.getBootloaderElf());
        gdb.setText(configDataModel.getGdbExe());
    }

    @Override
    protected void applyEditorTo(@NotNull EspIdfDebugRunConfig<CustomDebugConfigModel> espIdfDebugRunConfig) throws ConfigurationException {
        if (StringUtils.isEmpty(gdb.getText())) {
            throw new ConfigurationException($i18n("esp.idf.debugging.gdb.not.selected"));
        }
        if (StringUtils.isEmpty(appElf.getText())) {
            throw new ConfigurationException($i18n("esp.idf.debugging.app.elf.not.selected"));
        }
        CustomDebugConfigModel configDataModel = espIdfDebugRunConfig.getConfigDataModel();
        CustomDebugConfigModel customDebugConfigModel = configDataModel == null ? new CustomDebugConfigModel() : configDataModel;
        espIdfDebugRunConfig.setConfigDataModel(customDebugConfigModel);
        customDebugConfigModel.setAppElf(appElf.getText());
        customDebugConfigModel.setBootloaderElf(bootloaderElf.getText());
        customDebugConfigModel.setRomElf(romElf.getText());
        customDebugConfigModel.setOpenOcdArguments(arguments.getText());
        customDebugConfigModel.setGdbExe(gdb.getText());
        customDebugConfigModel.setEnvData(envComponent.getEnvData());
        IdfProfileInfo selectedIdfProfileInfo = project.getService(IdfProjectConfigService.class).getSelectedIdfProfileInfo();
        if (selectedIdfProfileInfo == null) {
            return;
        }
        customDebugConfigModel.setTarget(selectedIdfProfileInfo.getTarget());
    }

    @Override
    protected @NotNull JComponent createEditor() {
        return rootPanel;
    }

    private FileChooserDescriptor newElfFileChooser(String title, String description) {
        FileChooserDescriptor elf = FileChooserDescriptorFactory.createSingleFileDescriptor("elf");
        if (StringUtil.isNotEmpty(description)) {
            elf.setDescription(description);
        }
        if (StringUtil.isNotEmpty(title)) {
            elf.setTitle(title);
        }
        return elf;
    }

}
